package net

import (
	"fmt"
	"giot/pkg/logger"
	"net"
)

type UdpClient struct {
	Ip   string
	Port int

	running bool

	c *net.UDPConn

	dataArrival func(data []byte)
	stateChange func(state ConnectState)
}

// Connect 链接到服务
func (u *UdpClient) Connect(ip string, port int) error {
	var r = new(net.UDPAddr)
	r.IP = net.ParseIP(ip)
	r.Port = port

	udp, err := net.DialUDP("udp", nil, r)
	if err != nil {
		return err
	}
	u.c = udp
	u.Ip = ip
	u.Port = port
	u.running = true
	go func() {
		if u.stateChange != nil {
			u.stateChange(Connected)
		}
	}()

	go func() {
		for u.running {
			data := make([]byte, BuffSize)
			read, err2 := u.c.Read(data)
			if err2 != nil {
				u.running = false
				logger.GetLog().ErrorX(err2)
				if u.stateChange != nil {
					u.stateChange(ConnectedError)
				}
				return
			}
			if u.dataArrival != nil {
				u.dataArrival(data[:read])
			}
		}
	}()
	return nil
}

// Send 发送数据
func (u *UdpClient) Send(data []byte) (int, error) {
	if u.c == nil {
		return 0, fmt.Errorf("网络未连接,无法发送数据")
	}
	return u.c.Write(data)
}

// Close 关闭链接
func (u *UdpClient) Close() {
	u.running = false
	if u.c != nil {
		_ = u.c.Close()
	}
	u.c = nil
}

// OnDataArrival 数据到达回调函数
// func (data []byte): 数据到达回调函数
func (u *UdpClient) OnDataArrival(f func(data []byte)) {
	u.dataArrival = f
}

// OnStateChange 状态改变回调函数
func (u *UdpClient) OnStateChange(f func(state ConnectState)) {
	u.stateChange = f
}
